#!/usr/bin/env python3
'''
multipart/form-data 的post请求，可以使用外部模块poster或者requests
此模块使用内部模块构建
post_multipart(url, 
            [('pids', 'p_1'),('layout_1','C')],
            [('image_1', 'note.jpg', open('D:\\OscGit\\python\\res\\note.jpg','rb'))],
            [('Authorization','Bearer ' + self.access_token)])
'''

import http.client, mimetypes
import urllib

def post_multipart(url, fields, files, headers=None):
    """
    Post fields and files to an http host as multipart/form-data.
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return the server's response page.
    """
    content_type, coded_params = encode_multipart_formdata(fields, files)

    req = urllib.request.Request(url, coded_params.encode('ISO-8859-1'))
    req.add_header('Content-Type', content_type)
    for (head_title, head_val) in headers:
        req.add_header(head_title, head_val)
    try:
        resp = urllib.request.urlopen(req)
        return resp.read().decode('utf-8')
    except urllib.error.HTTPError as e:
        raise e

def encode_multipart_formdata(fields, files):
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, file) elements for data to be uploaded as files
    Return (content_type, coded_params) ready for http.client.HTTP instance
    """
    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
    CRLF = '\r\n'
    L = []
    for (key, v) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(v.encode('utf-8').decode('ISO-8859-1') if isinstance(v, str) else v.decode('ISO-8859-1'))
        print(key + '-------' + v)
    for (key, filename, file) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(file.read().decode('ISO-8859-1'))
    L.append('--' + BOUNDARY + '--')
    L.append('')

    coded_params = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, coded_params

def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
